package backend;

import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.*;

import backend.Task.State;


public class TaskManager {
  
	public static final int SIZE = 999;
	int overdueCount, doneCount, uncompletedCount;
	private int lastUpdatedTaskidx; Task lastUpdatedTask; boolean isRemoveDone;

	ArrayList<String> output = new ArrayList<String>();
	ArrayList<Task> outputViewList = null;
	
	ArrayList<Task> everything;
	ArrayList<Task> doneList;
	ArrayList<Task> overdueList;
	ArrayList<Task> viewList; // to store tasks that are viewed
	
	TimeDateValidator timedateValidator = new TimeDateValidator();
  
	public TaskManager(){
		everything = new ArrayList<Task>(SIZE); 
		doneList = new ArrayList<Task>(SIZE);
		overdueList = new ArrayList<Task>(SIZE);
		viewList = new ArrayList<Task>(SIZE);
    }
  
	/**
	 * This methods interprets what has been entered by the user according
	 * to several parameters as indicated by the first character of each Field Parameters.
	 * 
	 * @param item  The String of command as entered by the user.
	 */
	public void AddTask(String[] item)  {
		try {
			boolean Importance = false;
			boolean alarm = false;
			boolean TaskSetCorrect = true;
			int i=0,j=0;
			char[] temp;
			String TaskDescription="";
			String tempWord="";
			int dd=0,mm=0,yy=0;
			
			//Attributes to be stored in XML
			int StartTime=0,DueTime=0;
			String StoreVenue="-";
			String StoreLabel="-";
			String StoreTask="-";
			String ddmmyy="-"; 
			String StartTimeString="0";
			String DueTimeString="0"; 
			//Ends here
	
			for(j=1; j<item.length; j++) {
				
				temp = item[j].toCharArray();
				
				if(item[j].equals("+*")) {
					Importance = true;
				}
				
				if(temp[0] == '@') {
					if(temp.length==5) {
						StartTime = timedateValidator.StartTime(item[j]);
						StartTimeString = timedateValidator.GetStartTime(temp);
						DueTime = timedateValidator.StartTime(item[j]);
						DueTimeString = timedateValidator.GetStartTime(temp);
						if(!timedateValidator.CheckTime(DueTimeString)) {
							output.add("Invalid Time");
							TaskSetCorrect = false;
						}
					}
					else if(temp.length==10) {
						StartTime = timedateValidator.StartTime(item[j]);
						StartTimeString = timedateValidator.GetStartTime(temp);
						DueTime = timedateValidator.DueTime(item[j]);
						DueTimeString = timedateValidator.GetDueTime(temp);
						if(!timedateValidator.CheckTime(DueTimeString) && !timedateValidator.CheckTime(StartTimeString)) {
							output.add("Invalid Time");
							TaskSetCorrect = false;
						}
					}
					else {
						output.add("Invalid Time");
						TaskSetCorrect = false;
					}
				}
				
				if(temp[0] == '#') {
					tempWord = timedateValidator.CheckDate(temp);
					if(!tempWord.isEmpty()) {
						dd=timedateValidator.ConvertDateDD(tempWord);
						mm=timedateValidator.ConvertDateMM(tempWord);
						yy=timedateValidator.ConvertDateYY(tempWord);
						ddmmyy = tempWord;
					}
					else {
						output.add("Invalid Date");
						TaskSetCorrect = false;
					}
				}
				
				if(temp[0] == '$') {
					tempWord = GetWord(temp);
					StoreVenue = tempWord;
				}
				
				if(temp[0] == ':') {
					tempWord = GetWord(temp);
					StoreLabel = tempWord;
				}
				
				if(temp[0] == '*' || item[j].equals("+*")) {
					Importance = true;
					if(temp.length>2){
						TaskSetCorrect = false;
						output.add("Error at *");
					}
				}
				
				if(temp[0] == '!') {
					if(item[j].equals("!on")) {
						alarm = true;
						output.add("Alarm ON");
					}
					else if(item[j].equals("!off")) {
						alarm = false;
						output.add("Alarm OFF");
					}
					else {
						TaskSetCorrect = false;
						output.add("Error at !");
					}
				}
	
				if(temp[0]!='*' && temp[0]!='#' && temp[0]!='@' && temp[0]!='$' && temp[0]!='+' && temp[0]!=':' && temp[0]!='!') {
					TaskDescription = TaskDescription + item[j]+' ';
				}
			}
			
			//if Date is not set, assume today
			if(ddmmyy.equals("-") && !DueTimeString.equals("0")) {
				Format formatter;
				Date date = new Date();
			    formatter = new SimpleDateFormat("ddMMyy");
			    String s = formatter.format(date);
			    ddmmyy = s;
			    dd=timedateValidator.ConvertDateDD(ddmmyy);
				mm=timedateValidator.ConvertDateMM(ddmmyy);
				yy=timedateValidator.ConvertDateYY(ddmmyy);
			}
			
			//if Date is set, time not set, set time to 8am
			if(!ddmmyy.equals("-") && DueTimeString.equals("0")) {
				StartTimeString = "0800";
				DueTimeString = "0800";
			}
			
			if(TaskDescription.equals("-")) {
				System.out.println("No Task Description");
				TaskSetCorrect = false;
			}
			else {
				StoreTask = TaskDescription;
			}
			
			if(TaskSetCorrect) {
				Task newTask = new Task(dd, mm, yy, StartTimeString, DueTimeString, StoreLabel, Importance, StoreTask, StoreVenue, alarm);
				everything.add(newTask);	//pass the whole object
				sortList(everything);		// call sort method to sort the Task objects according to upcoming
				lastUpdatedTask = newTask;
				output.add("Task added");
				outputViewList = viewbyAll();
			}
			else {
				output.add("No task stored");	
			}
		} catch (NumberFormatException nfe) {
			 System.out.println("Please enter a integer");
			}
	}

	/**
	 * This methods take in a word in Character Array format and removes the first letter.
	 * 
	 * @param temp  ie, $Venue and :Label
	 * @return tempWord  ie, Venue, Label
	 */
	public String GetWord(char[] temp) {
		int k=1;
		String tempWord="";
		while(k<temp.length) {
			tempWord = tempWord + temp[k];
			k++;
		}
		return tempWord;
	}

	/**
	 * This method removes task based on the index given by user.
	 * ie, "- 2" would remove task 2, in the corresponding State that the program is in.
	 * State indicates whether the user is viewing the 'done' task list, 'overdue' task list and such.
	 * 
	 * @param item
	 */
	public void RemoveTask(String[] item) {
		int taskno=0;
		try {
			if(item.length<2) return;
			taskno = Integer.parseInt(item[1]);
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();	 System.out.println("Please enter a integer");
		}
		//ensure valid task id
		if(taskno > viewList.size() || taskno <= 0) { 
			output.add("Invalid Task ID");
			return;
		}
		//get the selected task
		int index = taskno-1;
		Task task = viewList.get(index);
		ArrayList<Task> targetList = null;
		
		//find which list the task is in
		State curList = task.getState();
		if(curList == Task.State.OVERDUE) {targetList = overdueList;}
		if(curList == Task.State.DONE) {targetList = doneList;}
		if(curList == Task.State.UPCOMING) {targetList = everything;}
		if(curList == Task.State.NODATETIME) {targetList = everything;}
		if(curList== null) return; //all List empty, do nothing, prevent exception calls
		
		//remove from the curList
		targetList.remove(viewList.get(index));
		viewList.remove(index);
		
		//alert the user what is done
		isRemoveDone = true;
		lastUpdatedTaskidx = index;
		output.add("Task \""+task.getDescription()+"\" deleted");
	}
	
	/**
	 * This method changes the Status of the Task to Done as indicated by the
	 * command given by the user.
	 * 
	 * @param item
	 */
	public void DoneTask(String[] item) {
		int taskno=0;
		try {
			if(item.length<2) return;
			taskno = Integer.parseInt(item[1]);
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();	System.out.println("Please enter a integer");
		}
		//ensure valid task id
		if(taskno > viewList.size() || taskno <= 0) { 
			output.add("Invalid Task ID");
			return;
		}
		//get the selected task
		int index = taskno-1;
		Task task = viewList.get(index);
		ArrayList<Task> targetList = null;
		
		//find which list the task is in
		State curList = task.getState();
		if(curList == Task.State.OVERDUE) {targetList = overdueList;}
		if(curList == Task.State.UPCOMING) {targetList = everything;}
		if(curList == Task.State.NODATETIME) {targetList = everything;}
		if(curList == Task.State.DONE) {
			targetList = null; 
			output.add("This task already completed");
			return;
		}
		if(curList == null) return; //all List empty, do nothing, prevent exception calls
		
		//remove task from curList
		targetList.remove(task);
		viewList.remove(index);
		
		//move task to doneList and set state as 'DONE'
		doneList.add(task);
		task.setState(Task.State.DONE);
		
		//alert the user what is done
		isRemoveDone = true;
		lastUpdatedTaskidx = index;
		output.add("Task \""+task.getDescription()+"\" completed");	
	}
	
	public void DoneTask(Task task) {
		//this method will only be modifying tasks with state 'UPCOMING'
		//remove task from curList, ie everythingList
		everything.remove(task);
		viewList.remove(task);
		
		//move task to doneList and set state as 'DONE'
		doneList.add(task);
		task.setState(Task.State.DONE);
		
		//alert the user what is done
		output.add("Task \""+task.getDescription()+"\" completed");
	}
	
	/**
	 * This method changes the status of a Done-d task to Undone or Upcoming or Overdue.
	 * ie, "undone 2" would change the status of Task 2 in the Done task list to Upcoming or 
	 * Overdue depending on its due date.
	 * 
	 * @param item
	 */
	public void UnDoneTask(String[] item) {
		int taskno=0;
		try {
			if(item.length<2) return;
			taskno = Integer.parseInt(item[1]);
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();	System.out.println("Please enter a integer");
		}
		//ensure valid task id
		if(taskno > viewList.size() || taskno <= 0) { 
			output.add("Invalid Task ID");
			return;
		}
		//get the selected task
		int index = taskno-1;
		Task task = viewList.get(index);
		ArrayList<Task> targetList = null;
		
		//find which list the task is in
		State curList = task.getState();
		if(curList != Task.State.DONE) {output.add("This task is not done yet"); return;}
		if(curList == Task.State.DONE) {targetList = doneList;}
		if(curList == null) return; //all List empty, do nothing, prevent exception calls
		
		//remove from the curList
		targetList.remove(task);
		viewList.remove(index);
		
		////////////////
		ModifyTaskParser(item, task);
		////////////////

		//check which list the updated task should go
		Calendar curCal = Calendar.getInstance();
		Calendar taskCal = task.getCal();
		boolean isOverdue = curCal.after(taskCal);
		
		//put updated task in the correct list and update its state
		if(!isOverdue) {	
			task.setState(Task.State.UPCOMING);
			everything.add(task); sortList(everything);
		} else {			//still overdue, need to update view
			task.setState(Task.State.OVERDUE);
			overdueList.add(task); sortList(overdueList);
		}
		
		//alert the user what is done
		isRemoveDone = true;
		lastUpdatedTaskidx = index;
		output.add("Task \""+task.getDescription()+"\" undone");
	}
		
	/**
	 * This method takes in the String command as entered by the user.
	 * This command is associated with Viewing of lists. ie, "view all" or "v done" 
	 * If "v #t" is done, user will view the tasks due tomorrow"
	 * 
	 * It then calls for the corresponding methods to bring out the respective lists of tasks.
	 * 
	 * @param item
	 * @return
	 */
	public int ViewTask(String[] item) {
		char[] temp;
		String tempStr = "";
		String tempStr2 = "";
		
		try {
			if(item.length < 2) {output.add("Invalid View Input"); return 0;}
			
			temp = item[1].toCharArray();
			
			if(item[1].equals("all")) {
				outputViewList = viewbyAll();
			}
			else if(item[1].equals("upcoming")) {
				int n=50;
				if(item.length == 3) n = Integer.parseInt(item[2]);
				outputViewList = viewbyUpcoming(n);
			}
			else if(item[1].equals("impt") || item[1].equals("important") || item[1].equals("*")) {
				outputViewList = viewbyImportance();
			}
			else if(temp[0]=='#') {
				if(temp.length==7){
					tempStr = timedateValidator.CheckDate(temp); 
					if(tempStr.isEmpty())
						output.add("Invalid Date");
					else
						outputViewList = viewbyDate(Integer.parseInt(tempStr));
				}
				else if(temp.length==14){
					tempStr = timedateValidator.CheckDate(temp); 
					tempStr2 = timedateValidator.CheckDate2(temp); 
					if(tempStr.isEmpty() || tempStr2.isEmpty())
						output.add("Invalid Date");
					else
						outputViewList = viewbyDatetoDate(Integer.parseInt(tempStr),Integer.parseInt(tempStr2));
				}
				else if(temp[1]=='t') {
					tempStr = timedateValidator.Tomorrow(1);
					tempStr = timedateValidator.CheckDate(temp); 
					if(tempStr.isEmpty())
						output.add("Invalid Date");
					else
						outputViewList = viewbyDate(Integer.parseInt(tempStr));
				}
				else 
					output.add("Invalid View by Date input, try #ddmmyy or #ddmmyy-ddmmyy");
			}
			else if(temp[0]==':') {
				outputViewList = viewbyLabel(item[1]);
				if(outputViewList.isEmpty()) output.add("No task with that label, Note: case sensitive");
			}
			else if(item[1].equals("done")) {
				outputViewList = viewbyDone();
			}
			else if(item[1].equals("overdue")) {
				outputViewList = viewbyOverdue();
			}
			else if(item[1].equals("notes")) {
				outputViewList = viewbyNotes();
			}
			else output.add("Invalid View Input");
		} catch (NumberFormatException nfe) {
			 System.out.println("Please enter a integer");
			}
	return 1;	
	}
	
	/**
	 * This method allows the modification of Tasks through the String of 
	 * command entered by the user.
	 * 
	 * It also detects the State of the program that the program is in
	 * to do the appropriate actions.
	 * 
	 * @param item
	 * @return  ArrayList of Task to be displayed in the GUI
	 */
	public ArrayList<Task> SearchTask(String[] item) {
		viewList.clear();
	    String keyword_lower = item[1].toLowerCase(); 
	    Task task = new Task();
	    
	    for (int i=0; i<everything.size(); i++) {
	    	task = everything.get(i);
	      
	    	String date = Integer.toString(task.getDate());
	    	String month = Integer.toString(task.getMonth());
	    	String year = Integer.toString(task.getYear());
	    	String starttime = Integer.toString(task.getStartTime());
	    	String endtime = Integer.toString(task.getEndTime());
	    
	    	if ((date.indexOf(keyword_lower)!=-1) || (month.indexOf(keyword_lower)!=-1) || (year.indexOf(keyword_lower)!=-1) || 
	    			(starttime.indexOf(keyword_lower)!=-1) || (endtime.indexOf(keyword_lower)!=-1) || (task.getDescription().toLowerCase().indexOf(keyword_lower)!=-1) || 
	    			(task.getLabel().toLowerCase().indexOf(keyword_lower)!=-1) || (task.getVenue().toLowerCase().indexOf(keyword_lower)!=-1)) 
	    	{
	    		viewList.add(task);
	    	}
	    }
	return viewList;
	}
	
	/**
	 * This method is called when user enters "mod ..."
	 * It identify the fields to be modified in the respective task and makes the necessary 
	 * changes to the task.
	 * 
	 * @param item
	 */
	public void ModifyTask(String[] item) {
		int taskno=0;
		try {
			if(item.length<2) return;
			taskno = Integer.parseInt(item[1]);
		} catch (NumberFormatException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();	System.out.println("Please enter a integer");
		}
		//ensure valid task id
		if(taskno > viewList.size() || taskno <= 0) { 
			output.add("Invalid Task ID");
			return;
		}
		//get the selected task
		int index = taskno-1;
		Task task = viewList.get(index); //index of what he wants to modify;
		ArrayList<Task> targetList = null;
		
		//put updated task in the correct list and update its state
		State curList = task.getState();
		if(curList == Task.State.OVERDUE) {targetList = overdueList; }//System.out.println("OVERDUE");}
		if(curList == Task.State.DONE) {targetList = doneList; }//System.out.println("DONE");}
		if(curList == Task.State.UPCOMING) {targetList = everything; }//System.out.println("EVERYTHING");}
		if(curList == Task.State.NODATETIME) {targetList = everything; }
		if(targetList == null) return; //all List empty, do nothing, prevent exception calls
	
		//remove from the curList
		viewList.remove(index);
		targetList.remove(task);
		
		////////////////
		ModifyTaskParser(item, task);
		///////////////
	
		//check which list the updated task should go
		Calendar curCal = Calendar.getInstance();
		Calendar taskCal = task.getCal();
		boolean isOverdue = curCal.after(taskCal);
	
		//to cater to postponing of overdue task
		switch (curList){
		case UPCOMING:
			if(isOverdue) { 	//Task overdue, do not need to update view
				task.setState(Task.State.OVERDUE);
				overdueList.add(task); sortList(overdueList);
			} else {			//Task still a upcoming need to update view
				task.setState(Task.State.UPCOMING);
				everything.add(task); sortList(everything);
				viewList.add(task); sortList(viewList);
			}
			break;
		case OVERDUE:	
			if(!isOverdue) {	//user postponed a task, no longer overdue, no need to update view
				task.setState(Task.State.UPCOMING);
				everything.add(task); sortList(everything);
			} else {			//still overdue, need to update view
				task.setState(Task.State.OVERDUE);
				overdueList.add(task); sortList(overdueList);
				viewList.add(task); sortList(viewList);
			}
			break;
		case DONE:				//task already done, no need to check for overdue, update view with modified task
			task.setState(Task.State.DONE);
			doneList.add(task); sortList(doneList);
			viewList.add(task); sortList(viewList);
			break;
		case NODATETIME:		//task from NoDATETIME to have
			Calendar noCal = Calendar.getInstance();
			noCal.set(2000, -1, 0, 0, 0, 0);
			if(taskCal.equals(noCal)) {
				task.setState(Task.State.NODATETIME);
				everything.add(task); sortList(everything);
				viewList.add(task); sortList(viewList);
				break;
			}
			if(!isOverdue) {	//new date is in the future
				
			} else {			//new date has passed
				task.setState(Task.State.OVERDUE);
				overdueList.add(task); sortList(overdueList);
			}
			break;
		}
		
		//alert the user what is done
		lastUpdatedTask = task;
		output.add("Task \""+task.getDescription()+"\" modified");
	}
	
	/**
	 * This method is called when the Modify task is to be done through the 
	 * Alarm/Reminder Popup window. 
	 * 
	 * The rest of the method is the same as above.
	 * 
	 * @param item  The String command entered in the Alarm/Reminder Popup window.
	 * @param task  The Task that caused the Popup Reminder/Alarm.
	 */
	public void ModifyTask(String[] item, Task task){
		/////////
		ModifyTaskParser(item, task);
		/////////
		
		//this method will only be modifying tasks with state 'UPCOMING'
		sortList(everything);
		sortList(viewList);
		
		output.add("Task \""+task.getDescription()+"\" modified");	
	}
	
	
	/**
	 * This method parse the String of command as entered by the user.
	 * It identifies the various fields to be modified and does the corresponding changes.
	 * 
	 * ie, "mod 2 #131212", this will change the due date of Task 2 to 131212 in ddMMyy
	 * This above example, Task 2, needs to be extracted and passed to this method.
	 * 
	 * @param item  
	 * @param task  Task to be modified. 
	 */
	public void ModifyTaskParser(String[] item, Task task){
		char[] temp;
		String tempWord="", TaskDescription="";
		
		for(int i=2; i<item.length; i++){
			temp = item[i].toCharArray();
			
			if(temp[0]=='$') {
				task.venue = GetWord(temp);
			}
			if(temp[0]==':') {
				task.label = GetWord(temp);
			}
			if(temp[0] == '#') {
				tempWord = timedateValidator.CheckDate(temp);
				if(!tempWord.isEmpty()) {
					task.dd=timedateValidator.ConvertDateDD(tempWord);
					task.mm=timedateValidator.ConvertDateMM(tempWord);
					task.yy=timedateValidator.ConvertDateYY(tempWord);
				}
				else {
					output.add("Invalid Date");
				}
			}
			if(temp[0] == '@') {
				if(temp.length==5) {
					task.starttime = timedateValidator.StartTime(item[i]);
					task.strStartTime = timedateValidator.GetStartTime(temp);
					task.endtime = timedateValidator.StartTime(item[i]);
					task.strEndTime = timedateValidator.GetStartTime(temp);
					if(!timedateValidator.CheckTime(task.strEndTime)) {
						output.add("Invalid Time");
					}
				}
				else if(temp.length==10) {
					task.starttime = timedateValidator.StartTime(item[i]);
					task.strStartTime = timedateValidator.GetStartTime(temp);
					task.endtime = timedateValidator.DueTime(item[i]);
					task.strEndTime = timedateValidator.GetDueTime(temp);
					if(!timedateValidator.CheckTime(task.strEndTime) && !timedateValidator.CheckTime(task.strStartTime)) {
						output.add("Invalid Time");
					}
				}
				else if(temp.length==4) {
				}
				else {
					output.add("Invalid Time");
				}
			}
			if(temp[0] == '*') {
				task.hasImportance = true;
				if(temp.length>1){
					output.add("Error at *");
				}
			}
			if(item[i].equals("+*")) {
				task.hasImportance = true;
				if(temp.length>2){
					output.add("Error at *");
				}
			}
			else if(item[i].equals("-*")) {
				task.hasImportance = false;
				if(temp.length>2){
					output.add("Error at *");
				}
			}
			if(temp[0]!='*' && temp[0]!='#' && temp[0]!='@' && temp[0]!='$' && temp[0]!='+' && temp[0]!=':' && temp[0]!='!' && temp[0]!='-') {
				TaskDescription = TaskDescription + item[i]+' ';
				task.description = TaskDescription.trim();
			}
			if(temp[0] == '!') {
				if(item[i].equals("!on")) {
					task.alarm = true;
					output.add("Alarm ON");
				}
				else if(item[i].equals("!off")) {
					task.alarm = false;
					output.add("Alarm OFF");
				}
				else {
					output.add("Error at !");
				}
			}
		}
	}

	/**
	 * This method calls for the ExportXML method which allows generating of XML files
	 * to store the respective lists for easy exporting.
	 * 
	 * When "save" is detect, all 3 lists will be stored in XML files.
	 * If a filename is detected, the Upcoming task list will be saved into XML file 
	 * of the filename indicated.
	 * 
	 * @param item
	 */
	public void ExportTask(String[] item) {
		FileIO fileIO = new FileIO();
		char[] fileformat;
		
		if(item[0].equals("save")){
			fileIO.ExportXML("SaveList.xml", everything);
			fileIO.ExportXML("doneList.xml", doneList);
			fileIO.ExportXML("overdueList.xml", overdueList);
		}
		else {
			fileformat = item[1].toCharArray();
			System.out.println("Export "+item[1]);
			fileIO.ExportXML(item[1], everything);
		}
		
	}
	
	
	/**
	 * This method calls for the ImportXML method that reads the tasks stored 
	 * in the XML files so as to be used by the user.
	 * 
	 * If "import ~" detected, it will load the 3 XML files that allows full functionality of the program.
	 * If "import <filename>" is detected, it will load the tasks in the file, into the program.
	 * 
	 * @param item
	 */
	public void ImportTask(String[] item) {
		FileIO fileIO = new FileIO();
		if(item[1].equals("~")) {
			System.out.println("Import SaveList.xml");
			everything.addAll(fileIO.ImportXML("SaveList.xml"));
			sortList(everything);
			System.out.println("Import overdueList.xml");
			overdueList.addAll(fileIO.ImportXML("overdueList.xml"));
			sortList(overdueList);
			System.out.println("Import doneList.xml");
			doneList.addAll(fileIO.ImportXML("doneList.xml"));
			sortList(doneList);
		}
		else {
			System.out.println("Import "+item[1]);
			everything.addAll(fileIO.ImportXML(item[1]));
			sortList(everything);
		}
	}
	
	/**
	 * This method allows the viewing of all upcoming tasks/tasks that have not been done.
	 * This list will include Notes type of Tasks (those with no Time and Date).
	 * 
	 * @return  ArrayList of Task to be displayed on GUI
	 */
	public ArrayList<Task> viewbyAll() {
		viewList.clear();
		Task taskInList;
		int size = everything.size();
    
		for (int i=0; i<size; i++) {
			taskInList = everything.get(i);
			viewList.add(taskInList);
		}
		
		output.add("Viewing all un-completed tasks");
		return viewList;
	}
  
	/**
	 * This method allows the viewing of all upcoming tasks/tasks that have not been done.
	 * This list will NOT include Notes type of Tasks.
	 * 
	 * @return  ArrayList of Task to be displayed on GUI
	 */
	public ArrayList<Task> viewbyUpcoming(int index) { // index is the number of next upcoming tasks
		viewList.clear();
		Task taskInList = null;
		
		for (int i=0; i<everything.size(); i++) {
			if(index == 0) break;
			taskInList = everything.get(i);
			if(taskInList.getState() != Task.State.NODATETIME) {
				viewList.add(taskInList);
				index--;
			}	
		}	
		
		output.add("Viewing upcoming task...");
		return viewList;
	}
	
	/**
	 * This method allows the viewing of all Overdue tasks/tasks that have not been done
	 * and has passed the due time or date.
	 * 
	 * @return  ArrayList of Task to be displayed on GUI
	 */
	public ArrayList<Task> viewbyOverdue() {
		viewList.clear();
		Task taskInList = null;
		
		for (int i=0; i<overdueList.size(); i++) {
			taskInList = overdueList.get(i);
			viewList.add(taskInList);	
		}
		
		output.add("Viewing overdue tasks...");
		output.add("Use modify to postpone tasks");
		return viewList;
	}
	
	/**
	 * This method allows the viewing of all Notes type of Tasks (Tasks with no due time and date).
	 *  
	 * @return  ArrayList of Task to be displayed on GUI
	 */
	public ArrayList<Task> viewbyNotes() {
		viewList.clear();
		Task taskInList = null;
		Calendar noCal = Calendar.getInstance();
		noCal.set(2000, -1, 0, 0, 0, 0);
		Calendar taskCal = Calendar.getInstance(); 
    
		for (int i=0; i<everything.size(); i++) {
			taskInList = everything.get(i);
			taskCal.set(taskInList.getYear4(), taskInList.getMonth()-1, taskInList.getDate(), 
					taskInList.getStartTimehours(), taskInList.getStartTimeminutes(), 0); //note jan is zero, dec is 11!
			
			if(taskCal.equals(noCal)) {viewList.add(taskInList);}
		}
		
		output.add("Viewing notes...");
		return viewList;
	}
  
	/**
	 * This method allows the viewing of tasks according to the date entered
	 * by the user. 
	 * 
	 * ie, "v #170612" or "v #t", extract the date in Integer and call for this Method
	 * 
	 * @param index  Date as indicated by user.
	 * @return  ArrayList of Task to be displayed on GUI
	 */
	public ArrayList<Task> viewbyDate (int index) { // viewlist by date
		viewList.clear();
		Task taskinlist;
		int year = index%100;
		int month = (index/100)%100;
		int date = ((index/100)/100)%100;
		int size = everything.size();
    
		for (int i=0; i<size; i++) {
			taskinlist = everything.get(i);
			if (taskinlist.getYear() == year && taskinlist.getMonth() == month && taskinlist.getDate() == date)
				viewList.add(taskinlist);
		}
		
		output.add("Viewing tasks on #"+index+" ...");
		return viewList;
	}
  
	/**
	 * This method allows the viewing of tasks according to the range of date entered
	 * by the user. 
	 * 
	 * ie, "v #170612-200612", extract the dates and call for this method
	 * 
	 * @param startDate  
	 * @param endDate
	 * @return  ArrayList of Task to be displayed on GUI
	 */
	public ArrayList<Task> viewbyDatetoDate (int startDate, int endDate) { // viewlist by start date to end date
		viewList.clear();
		Task taskinlist;
		int year1 = startDate%100;
		int month1 = (startDate/100)%100;
		int date1 = (startDate/10000)%100;
		int year2 = endDate%100;
    	int month2 = (endDate/100)%100;
    	int date2 = (endDate/10000)%100;
    	int size = everything.size();
    
    	Calendar startdate = Calendar.getInstance();
    	Calendar enddate = Calendar.getInstance();
    	startdate.set(year1, month1, date1);
    	enddate.set(year2, month2, date2);
    	Calendar taskdate = Calendar.getInstance();
    	
    	for (int i=0; i<size; i++) {
    		taskinlist = everything.get(i);
    		taskdate.set(taskinlist.getYear(), taskinlist.getMonth(), taskinlist.getDate());
    		if(taskdate.after(startdate) && taskdate.before(enddate) || taskdate.equals(startdate) || taskdate.equals(enddate))
    			viewList.add(taskinlist);
    	}
    	
    	output.add("Viewing tasks from #"+startDate+"-#"+endDate);
    	return viewList;
    }
  
	 /**
	 * This method allows the viewing of Tasks by their Labels.
	 * 
	 * ie, "view :Sports", just call for this method using "Sports"
	 * 
	 * @param label
	 * @return  ArrayList of Task to be displayed on GUI
	 */
	public ArrayList<Task> viewbyLabel (String label) { // viewlist by label, String para in the form :label
		 viewList.clear();
		 String temp= ":";
		 
		 for (int i=0; i<everything.size(); i++) {
			 temp = temp + everything.get(i).label;
			 if (temp.equals(label)){
				 viewList.add(everything.get(i)); 
			 }
			 temp= ":";
		 }
		 
		 output.add("Viewing tasks labelled "+label);
		 return viewList;
	 }
  
	 /**
	 * This method allows the viewing of Tasks via their Importance.
	 * 
	 * @return  ArrayList of Task to be displayed on GUI
	 */
	public ArrayList<Task> viewbyImportance() { // 1 = important
		 viewList.clear();
		 
		 for (int i=0; i<everything.size(); i++) {
			 if (everything.get(i).hasImportance){
				 viewList.add(everything.get(i));
			 }
		 }
		 
		 output.add("Viewing all Impt Tasks...");
		 return viewList;
	 }
	 
	 /**
	 * This method allows the viewing of Tasks that has be marked as Done.
	 * 
	 * @return  ArrayList of Task to be displayed on GUI
	 */
	public ArrayList<Task> viewbyDone() {
		 viewList.clear();
		 viewList = new ArrayList<Task>(doneList);

		 output.add("Viewing completed tasks...");
		 return viewList;
	 }

	 /**
	 * This method does the sorting of the Tasks according to its Date.
	 *  
	 * @param aList  The ArrayList of Task to be sorted.
	 */
	public void sortList(ArrayList<Task> aList) {
		 int size = aList.size();
		 if(size == 0) return;
		 
		 int a, i, j=0;
		 Task temp1, temp2;
    
		 for (a=0; a<size; a++) {
			 for (i=1; i<size; i++) {
				 j = i - 1;
				 temp1 = aList.get(j);
				 temp2 = aList.get(i);
        
				 Calendar date1 = Calendar.getInstance();
				 Calendar date2 = Calendar.getInstance();
        
				 date1.set(temp1.getYear(), temp1.getMonth(), temp1.getDate(), temp1.getStartTimehours(), temp1.getStartTimeminutes());
				 date2.set(temp2.getYear(), temp2.getMonth(), temp2.getDate(), temp2.getStartTimehours(), temp2.getStartTimeminutes());
        
				 if(date1.after(date2)){
					 aList.set(i, temp1);
					 aList.set(j, temp2);
				 }	
			 }
		 } 
	 }

	/**
	 * This method is executed when the Current time passes the Due time and Date
	 * of a Task and therefore making the Task overdue.
	 * 
	 * @param task  Task that is Overdue.
	 * @return
	 */
	public int setTaskOverdue(Task task) {
		if(task == null) return -1;
		
		//remove from the curList
		everything.remove(task);
		viewList.remove(task);
		
		//put updated task in the correct list and update its state
		overdueList.add(task);
		task.setState(State.OVERDUE);

		output.add("Task: "+task.getDescription()+" has overdue.");
		return 1;
	}
	
	/**
	 * The following 3 methods returns the number of Tasks stored in
	 * each list so as to be displayed on the GUI.
	 * 
	 * @return
	 */
	public int getOverdueCount(){
		overdueCount = overdueList.size();
		return overdueCount;
	}

	public int getUncompletedCount(){
		uncompletedCount = everything.size();
		return uncompletedCount;
	}
	
	public int getDoneCount(){
		doneCount = doneList.size();
		return doneCount;
	}	
	
	public Task getNextTask(){
		if(everything.isEmpty()) return null;
		
		Task task;
		for (int i=0; i<everything.size(); i++) {
			task = everything.get(i);
			if(task.getState() != Task.State.NODATETIME) {
				return task; //found task, filters out notes 
			}
		}	
		return null;
	}
	
    /**
     * Helper message 
     * @return
     */
    public ArrayList<String> out(){
    	return output;
    }
    
    /**
     * Actual view of tasks stored
     * @return
     */
    public ArrayList<Task> outTable(){
    	return outputViewList;
    }
    
    /**
     * This method is used in the process of displaying Text in the GUI.
     * 
     * @param text  The String to be displayed
     */
    public void DisplayText(String text) {
    	output.add(text);
    }
    
    public int getTaskIndex(){
		if(isRemoveDone) {
			if(lastUpdatedTaskidx <= viewList.size()-1)	
				{isRemoveDone = false; return lastUpdatedTaskidx;}
			else {int idx = lastUpdatedTaskidx -1; return idx;}
		}
		int index = viewList.indexOf(lastUpdatedTask);
		return index;
	}
}
